﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace katOS
{
    /// <summary>
    /// Class that represents the PCB 
    /// It has the information on every process created
    /// </summary>
    class Process
    {
        int pid;    //Process ID
        int state;  //Process state
        int end_value; //value thar returns after ending a process
        //See if this variable is used for something
        int ip;     //Instruction pointer

        volatile string file_name = "";
        string out_file;
        volatile StreamWriter file;

        bool sync = true;
        bool reach_end = false;

        int r0, r1, r2, r3, r4, r5, r6, r7;
        int parent_pid=-1; //Process ID of the parent process if there is one
        
        LinkedList<String> instructions_set;    //Set of instructions
        volatile string[,] symbolsTable;    //Symbols table for the code

        public volatile int priority;
        public int queue = -1;

        public int quantum_left = -1;
        public bool io_wait = false;
        public bool quantum_over = false;

        public int turn_around_time = 0;
        public int waiting_time = 0;
        public int response_time = 0;
        public bool has_responded = false;
        public int excecution_time = 0;
        public int io_waiting_time = 0;
        public int quantum_waiting_time = 0;
        public int semaphore_waiting_time = 0;

        /// <summary>
        /// Method to create a new instance of a process
        /// </summary>
        /// <param name="filename">The name of the file that excecutes the process</param>
        /// <param name="id">The process ID</param>
        /// </param name="pr">The process priority</param> 
        public Process(string filename, int id, int pr)
        {
            //check the log to write info about the process
            pid = id;
            file_name = filename;
            priority = pr;
            state = 1;
            sync = true;
            queue = Scheduler.start_queue;
            r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = end_value = 0;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="id"></param>
        /// <param name="pr"></param>
        /// <param name="outputFile"></param>
        public Process(string filename, int id, int pr, string outputFile)
        {
            //check the log to write info about the process
            pid = id;
            file_name = filename;
            priority = pr;
            state = 1;
            sync = false;
            r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = end_value = 0;
            queue = Scheduler.start_queue;
            out_file = outputFile;
            file = new StreamWriter("C:/Users/kareAndy/Documents/UVG/Ciclo 5/CC3002 Sistemas Operativos/Proyecto No. 1/katOSFiles/" + out_file);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="id"></param>
        /// <param name="parameters"></param>
        /// <param name="outputFile"></param>
        public Process(string filename, int id, int pr, int[]parameters, string outputFile)
        {
            pid = id;
            file_name = filename;
            priority = pr;
            state = 1;
            end_value = 0;
            sync = false;
            r0 = parameters[0];
            r1 = parameters[1];
            r2 = parameters[2];
            r3 = parameters[3];
            r4 = parameters[4];
            r5 = parameters[5];
            r6 = parameters[6];
            r7 = parameters[7];
            queue = Scheduler.start_queue;
            out_file = outputFile;
            try
            {
                file = new StreamWriter("C:/Users/kareAndy/Documents/UVG/Ciclo 5/CC3002 Sistemas Operativos/Proyecto No. 1/katOSFiles/" + out_file);
            }
            catch (Exception)
            {
                Console.WriteLine("The file can not be created");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="id"></param>
        /// <param name="parameters"></param>
        public Process(string filename, int id, int pr, int[] parameters)
        {
            pid = id;
            file_name = filename;
            priority = pr;
            state = 1;
            end_value = 0;
            sync = true;
            r0 = parameters[0];
            r1 = parameters[1];
            r2 = parameters[2];
            r3 = parameters[3];
            r4 = parameters[4];
            r5 = parameters[5];
            r6 = parameters[6];
            r7 = parameters[7];
            queue = Scheduler.start_queue;
        }

        public void addResponseTime()
        {
            if (excecution_time <= 0)
            {
                response_time++;
            }
        }

        public void addWaitingTime()
        {
            if (state == 4)
            {
                io_waiting_time++;
            }
            else if (state == 8)
            {
                quantum_waiting_time++;
            }
        }

        public void subQuantum()
        {
            quantum_left--;
            if (quantum_left == 0)
            {
                quantum_over = true;
            }
        }

        public void setQuantumLeft(int quantum)
        {
            quantum_left = quantum;
            if (quantum_left != 0)
            {
                quantum_over = false;
            }
        }

        /// <summary>
        /// Mehod that checks if the process has reach its end
        /// </summary>
        /// <returns>Returns true if the process has ended</returns>
        public bool hasReachedEnd()
        {
            return reach_end;
        }

        /// <summary>
        /// Method that returns the file that has the program
        /// </summary>
        /// <returns>Returns a file</returns>
        public StreamWriter getFile()
        {
            return file;
        }

        public void setSync(bool is_sync)
        {
            sync = is_sync;
        }

        /// <summary>
        /// Gets the type of synchrony of a process
        /// </summary>
        /// <returns>Returns true if is a sync process</returns>
        public bool getSync()
        {
            return sync;
        }

        public void setOutFile(string outFile)
        {
            out_file = outFile;
        }

        public string getOutFile()
        {
            return out_file;
        }


        /// <summary>
        /// Method that sets if the process has ended
        /// </summary>
        /// <param name="setend">Boolean that indicates if the process has ended</param>
        public void setEnd(bool setend)
        {
            reach_end = setend;
        }

        /// <summary>
        /// Method to initialize the registers
        /// </summary>
        /// <param name="reg_name">Name of the register</param>
        /// <param name="reg">Value for the register</param>
        public void setRegister(string reg_name, int reg)
        {
            switch (reg_name)
            {
                case "r0":
                    r0 = reg;
                    break;
                case "r1":
                    r1 = reg;
                    break;
                case "r2":
                    r2 = reg;
                    break;
                case "r3":
                    r3 = reg;
                    break;
                case "r4":
                    r4 = reg;
                    break;
                case "r5":
                    r5 = reg;
                    break;
                case "r6":
                    r6 = reg;
                    break;
                case "r7":
                    r7 = reg;
                    break;
                default:
                    Console.WriteLine("Not a register");
                    break;
            }
        }

        /// <summary>
        /// Method that returns a register
        /// </summary>
        /// <param name="reg_name">Name of the register</param>
        /// <returns></returns>
        public int getRegister(string reg_name)
        {
            switch (reg_name)
            {
                case "r0":
                    return r0;
                case "r1":
                    return r1;
                case "r2":
                    return r2;
                case "r3":
                    return r3;
                case "r4":
                    return r4;
                case "r5":
                    return r5;
                case "r6":
                    return r6;
                case "r7":
                    return r7;
                default:
                    Console.WriteLine("Not a register");
                    return -1;
            }
        }

        /// <summary>
        /// Method that returns the process ID
        /// </summary>
        /// <returns>Returns process ID</returns>
        public int getPID() 
        {
            return pid;
        }
        
        /// <summary>
        /// Method that sets the instruction pointer for a process
        /// </summary>
        /// <param name="ip">The value of the instruction pointer</param>
        public void setIP(int ip)
        {
            this.ip = ip;
        }

        /// <summary>
        /// Method that returns the instruction pointer
        /// </summary>
        /// <returns>Returns the IP</returns>
        public int getIP()
        {
            return ip;
        }

        /// <summary>
        /// Method that sets the process value
        /// </summary>
        /// <param name="value">The process value</param>
        public void setProcessValue(int value)
        {
            end_value = value;
        }

        /// <summary>
        /// Method that returns the process value
        /// </summary>
        /// <returns>Returns pvalue</returns>
        public int getProcessValue()
        {
            return end_value;
        }

        /// <summary>
        /// Method that returns the name of the process file
        /// </summary>
        /// <returns>The file name of the process</returns>
        public string getFileName()
        {
            return file_name;
        }

        /// <summary>
        /// Method that sets the state of the process
        /// </summary>
        /// <param name="state">The process state</param>
        public void setState(int state)
        {
            this.state = state;
            //write in logs the state
        }

        /// <summary>
        /// Method that returns the state of the process
        /// </summary>
        /// <returns>Returns the process state</returns>
        public int getState()
        {
            return state;
        }

        /// <summary>
        /// Method that sets a parent of a process if it has one
        /// </summary>
        /// <param name="parentpid">The process ID of the parent</param>
        public void setParent(int parentpid)
        {
            parent_pid = parentpid;
        }

        /// <summary>
        /// Method that returns the parent process
        /// </summary>
        /// <returns>Returns the process ID of the parent</returns>
        public int getParent()
        {
            return parent_pid;
        }

        /// <summary>
        /// Method that sets the instruction set of a process
        /// </summary>
        /// <param name="insts">List that contains the instruction set</param>
        public void setInstructions(LinkedList<String> insts)
        {
            instructions_set = insts;
        }

        /// <summary>
        /// Method that returns the instruction set
        /// </summary>
        /// <returns>Returns the instruction set</returns>
        public LinkedList<String> getInstructions()
        {
            return instructions_set;
        }

        /// <summary>
        /// Method that sets the symbols table of a process
        /// </summary>
        /// <param name="stable">The symbols table array</param>
        public void setSymbolsTable(string[,] stable)
        {
            symbolsTable = stable;
        }

        /// <summary>
        /// Method that returns the symbols table of the process
        /// </summary>
        /// <returns>Returns the symbols table array</returns>
        public string[,] getSymbolsTable()
        {
            return symbolsTable;
        }

        public void setQueue(int queue_num)
        {
            queue = queue_num;
        }

        public int getQueue()
        {
            return queue;
        }
    }
}